#ifndef __ELOG_H__
#define __ELOG_H__

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <pthread.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/timeb.h>

/* output log's level */
#define ELOG_LVL_ASSERT                      (0)
#define ELOG_LVL_ERROR                       (1)
#define ELOG_LVL_WARN                        (2)
#define ELOG_LVL_INFO                        (3)
#define ELOG_LVL_DEBUG                       (4)
#define ELOG_LVL_VERBOSE                     (5)

/* output log's level total number */
#define ELOG_LVL_TOTAL_NUM                   (6)

/* elog software version number */
#define ELOG_SW_VERSION                      "1.0.0"

/* all formats index */
typedef enum {
    ELOG_FMT_LVL    = 1 << 0, /**< level */
    ELOG_FMT_TAG    = 1 << 1, /**< tag */
    ELOG_FMT_TIME   = 1 << 2, /**< current time */
    ELOG_FMT_P_INFO = 1 << 3, /**< process info */
    ELOG_FMT_T_INFO = 1 << 4, /**< thread info */
    ELOG_FMT_FILE   = 1 << 5, /**< file directory and name */
    ELOG_FMT_FUNC   = 1 << 6, /**< function name */
    ELOG_FMT_LINE   = 1 << 7, /**< line number */
} ElogFmtIndex;

/* macro definition for all formats */
#define ELOG_FMT_ALL    (ELOG_FMT_LVL|ELOG_FMT_TAG|ELOG_FMT_TIME|ELOG_FMT_P_INFO|ELOG_FMT_T_INFO| \
    ELOG_FMT_FILE|ELOG_FMT_FUNC|ELOG_FMT_LINE)

#define getrlog() (&g_elog)
#define LOGNAME_DEFAULT "elog"
#define LOGPATH_DEFAULT "/"
#define DTIME_LEN   (22) //19700101|08:00:22.372
#define ELOG_BUF_SIZE (512)
#define SIZE (64)
#define ELOG_OUT_STDOUT (1)
#define ELOG_OUT_FILE   (2)
#define ELOG_LEVEL_SIZE (1)
#define ELOG_TAG_SIZE   (32)
#define ELOG_FILE_SIZE  (32)
#define ELOG_FUNC_SIZE  (32)
#define ELOG_LINE_SIZE  (5)
#define elog_print printf
#define elog_write(level, tag, ...) do{\
            elog_output_lock();\
            if(elog_output(level, tag, __FILE__, __FUNCTION__, __LINE__)){\
                elog_print(__VA_ARGS__);\
                elog_print("\n");\
            }\
            elog_fflush();\
            elog_output_unlock();\
        }while(0)

/* easy logger */
typedef struct {
    FILE        *fd;
    int         std;
    int         loglevel;
    size_t      fmt_set[ELOG_LVL_TOTAL_NUM];
    bool        output_enabled;
    pthread_mutex_t mutex;
}elog_t;


#define elog_a(tag, ...)    elog_assert(tag, __VA_ARGS__)
#define elog_e(tag, ...)    elog_error(tag, __VA_ARGS__)
#define elog_w(tag, ...)    elog_warn(tag, __VA_ARGS__)
#define elog_i(tag, ...)    elog_info(tag, __VA_ARGS__)
#define elog_d(tag, ...)    elog_debug(tag, __VA_ARGS__)
#define elog_v(tag, ...)    elog_verbose(tag, __VA_ARGS__)

#define elog_assert(tag, ...)       elog_write(ELOG_LVL_ASSERT, tag, __VA_ARGS__)
#define elog_error(tag, ...)        elog_write(ELOG_LVL_ERROR, tag, __VA_ARGS__)
#define elog_warn(tag, ...)         elog_write(ELOG_LVL_WARN, tag, __VA_ARGS__)
#define elog_info(tag, ...)         elog_write(ELOG_LVL_INFO, tag, __VA_ARGS__)
#define elog_debug(tag, ...)        elog_write(ELOG_LVL_DEBUG, tag, __VA_ARGS__)
#define elog_verbose(tag, ...)      elog_write(ELOG_LVL_VERBOSE, tag, __VA_ARGS__)

/* elog.c */
int elog_init(char *logname);
void elog_set_output_enabled(bool enabled);
bool elog_get_output_enabled(void);
void elog_set_fmt(int level, size_t set);
void elog_set_level(int level);
void elog_set_output(int out, const char* newfile);
void elog_output_lock(void);
void elog_output_unlock(void);
int elog_get_datetime(char *dtime, int len);
bool elog_output(int level, const char *tag, const char *file, const char *func, const long line);
void elog_fflush(void);
void elog_release();

#endif /* __ELOG_H__ */
